home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1997
/
HAM Radio 1997.iso
/
vcls
/
cltsvr
/
ftp.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-04-08
|
22KB
|
851 lines
unit Ftp;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Menus, Sockets, Login, FileGet, FilePut,
FileRen, FileView, IniFiles, Meter;
type
TFTPForm = class(TForm)
Sockets1: TSockets;
Sockets2: TSockets;
MainMenu1: TMainMenu;
FileMNU: TMenuItem;
ExitMNU: TMenuItem;
DirCommandMNU: TMenuItem;
ConnectMNU: TMenuItem;
DirMNU: TMenuItem;
GetMNU: TMenuItem;
PutMNU: TMenuItem;
ChDirMNU: TMenuItem;
MkDirMNU: TMenuItem;
RmDirMNU: TMenuItem;
QuitMNU: TMenuItem;
DeleteMNU: TMenuItem;
RenameMNU: TMenuItem;
PwdMNU: TMenuItem;
N1: TMenuItem;
FileTransMNU: TMenuItem;
HelpMNU: TMenuItem;
QuoteMNU: TMenuItem;
Memo1: TMemo;
MiscCommMNU: TMenuItem;
ViewMNU: TMenuItem;
CancelMNU: TMenuItem;
ParentMNU: TMenuItem;
OptionsMNU: TMenuItem;
DirSepMNU: TMenuItem;
ViewSepMNU: TMenuItem;
EditorMNU: TMenuItem;
procedure Sockets1ErrorOccurred(Sender: TObject; Error: Integer;
Msg: String);
procedure ConnectMNUClick(Sender: TObject);
procedure DirMNUClick(Sender: TObject);
procedure QuitMNUClick(Sender: TObject);
procedure GetMNUClick(Sender: TObject);
procedure PutMNUClick(Sender: TObject);
procedure ExitMNUClick(Sender: TObject);
procedure ChDirMNUClick(Sender: TObject);
procedure MkDirMNUClick(Sender: TObject);
procedure RmDirMNUClick(Sender: TObject);
procedure PwdMNUClick(Sender: TObject);
procedure RenameMNUClick(Sender: TObject);
procedure DeleteMNUClick(Sender: TObject);
procedure HelpMNUClick(Sender: TObject);
procedure QuoteMNUClick(Sender: TObject);
procedure EnableDisableMenus;
procedure FormCreate(Sender: TObject);
procedure ViewMNUClick(Sender: TObject);
procedure CancelMNUClick(Sender: TObject);
procedure ParentMNUClick(Sender: TObject);
procedure EditorMNUClick(Sender: TObject);
procedure DirSepMNUClick(Sender: TObject);
procedure ViewSepMNUClick(Sender: TObject);
private
procedure DoPrintf(line: string; const args: array of const);
function DoDirList(cmd: string;const args: array of const): integer;
function ReadDisplayLine: integer;
function GetFTPListenPort: integer;
procedure RetrieveFile(cmd: string;LocalName: string; rtype: string);
function TimedOut: Boolean;
function getreply(cmdstring: string): integer;
function command(fmt: string; const args: array of const): integer;
procedure DoAddLine(Buff: string);
procedure ImBusy;
procedure ImFree;
procedure UpdateGauge(BytesWritten,TotalTransferSize: longint);
procedure CancelGauge;
function GetTotalRetrieveSize: longint;
public
end;
const
FTP_PRELIM = 1;
FTP_COMPLETE = 2;
FTP_CONTINUE = 3;
FTP_RETRY = 4;
FTP_ERROR = 5;
var
FTPForm: TFTPForm;
line,GlobalBuff: string;
ErrorReturn: integer;
Aborted: Boolean;
Connected: Boolean;
CmdInProgress: Boolean;
DirSep, ViewSep, Editor: string;
implementation
{$R *.DFM}
procedure TFTPForm.Sockets1ErrorOccurred(Sender: TObject; Error: Integer;
Msg: String);
var
szMsg: array[0..255] of char;
begin
ErrorReturn := Error;
if Error = WSAETIMEDOUT then
begin
Aborted := True;
ErrorReturn := 0;
end
else
begin
StrPCopy(szMsg,'Error: '+IntToStr(Error)+#13#10+Msg);
Application.MessageBox(szMsg,'Error',MB_ICONEXCLAMATION);
end;
end;
procedure TFTPForm.RetrieveFile(cmd: string;LocalName: string; rtype: string);
var
FileName: string;
szFileName: array[0..255] of char;
RecvData: string;
IsDirList: Boolean;
IsView: Boolean;
Separate: Boolean;
szBuffer: array[0..255] of char;
output_file: integer;
iret: integer;
szTempFileName: array[0..63] of char;
szCmd: array[0..63] of char;
BytesWritten: longint;
TotalRetrieveSize: longint;
begin
BytesWritten := 0;
Aborted := False;
Separate := False;
output_file := 0;
{ determine what the retrieve is going to do...
1) Retrieve a file
2) Directory listing
2.1) inline
2.2) seperate editor session
3) View a file
3.1) inline
3.2) seperate editor session
}
if (LocalName = '') and (copy(cmd,1,4) <> 'LIST') then
begin { goal is to view the file }
IsView := True;
if ViewSep = '1' then {separately or inline?}
begin
Separate := True;
GetTempFileName(#0,'VIW',0,szTempFileName);
output_file := _lcreat(szTempFileName,0);
end;
end
else
IsView := False;
IsDirList := False;
if copy(cmd,1,4) = 'LIST' then {goal is to perform directory listing}
begin
IsDirList := True;
if DirSep = '1' then {separately or inline?}
begin
Separate := True;
GetTempFileName(#0,'LST',0,szTempFileName);
output_file := _lcreat(szTempFileName,0);
end;
end;
if not IsDirList then
begin
if not IsView then {goal is to retrieve a file}
begin
Separate := True;
StrPCopy(szFileName,LocalName);
output_file := _lcreat(szFileName,0);
if output_file = -1 then
begin
Application.MessageBox('Could not open file','_lopen error',MB_ICONEXCLAMATION);
output_file := 0;
exit;
end;
end;
end;
if command(rtype,[nil]) = FTP_ERROR then
exit;
Sockets2.NonBlocking := False;
Sockets2.Timeout := 30;
if GetFTPListenPort = FTP_ERROR then
begin
Sockets2.SCancelListen;
exit;
end;
if IsDirList then
begin
if Separate then
begin
command('PWD',[nil]);
StrPCopy(szBuffer,GlobalBuff);
_lwrite(output_file,szBuffer,StrLen(szBuffer));
StrPCopy(szBuffer,cmd+#13#10);
_lwrite(output_file,szBuffer,StrLen(szBuffer));
end;
Sockets1.Timeout := 0; {infinite timeout}
iret := command(cmd,[nil]);
Sockets1.Timeout := 30;
if (iret = FTP_RETRY) or (iret = FTP_ERROR) then
begin
DoPrintf('Could not list directory',[nil]);
Sockets2.SCancelListen;
exit;
end;
end
else
begin
iret := command('RETR %s',[cmd]);
if (iret = FTP_RETRY) or (iret = FTP_ERROR) then
begin
DoPrintf('Could not retrieve file',[nil]);
_lclose(output_file);
Sockets2.SCancelListen;
exit;
end;
TotalRetrieveSize := GetTotalRetrieveSize;
end;
ImBusy;
Sockets2.SAccept;
ImFree;
if TimedOut or (ErrorReturn <> 0) then
begin
Application.Messagebox('Could not extablish data socket, operation canceled',
'ERROR',MB_ICONEXCLAMATION);
exit;
end;
ImBusy;
repeat
RecvData := Sockets2.Text;
if Length(RecvData) > 0 then
begin
if (IsDirList) and (not Separate) then
DoAddLine(RecvData)
else
if (IsView) and (not Separate) then
DoAddLine(RecvData)
else
begin
StrPCopy(szBuffer,RecvData);
if _lwrite(output_file,szBuffer,Length(RecvData)) = -1 then
begin
DoPrintf('%sWrite to file: %s failed, transfer incomplete',
[#13#10,LocalName]);
Aborted := True;
end;
if not IsDirList then
begin
BytesWritten := BytesWritten + Length(RecvData);
UpdateGauge(BytesWritten,TotalRetrieveSize);
end;
end;
end;
if TimedOut then
begin
Sockets1.OOB := 'ABOR'+#13#10;
ReadDisplayLine;
end;
until Length(RecvData) <= 0;
ImFree;
if Separate then
begin
_lclose(output_file);
output_file := 0;
end;
if IsDirList or IsView then
if Separate then
begin
StrPCopy(szCmd,Editor+' ');
StrCat(szCmd,szTempFileName);
WinExec(szCmd,SW_SHOW);
end;
Sockets2.SCancelListen;
Sockets2.SClose;
ReadDisplayLine;
CancelGauge;
end;
function TFTPForm.GetFTPListenPort: integer;
var
i1,i2,i3,i4: integer;
IPAddr: string;
portcmd: string;
begin
Sockets2.Port := '0';
Sockets2.SListen;
IPAddr := Sockets1.GetIPAddr(Sockets1.SocketNumber);
i1 := StrToInt(copy(IPAddr,1,pos('.',IPAddr)-1));
IPAddr := copy(IPAddr,pos('.',IPAddr)+1,255);
i2 := StrToInt(copy(IPAddr,1,pos('.',IPAddr)-1));
IPAddr := copy(IPAddr,pos('.',IPAddr)+1,255);
i3 := StrToInt(copy(IPAddr,1,pos('.',IPAddr)-1));
i4 := StrToInt(copy(IPAddr,pos('.',IPAddr)+1,255));
portcmd := format('PORT %d,%d,%d,%d,%d,%d',[i1,i2,i3,i4,
StrToInt(Sockets2.GetPort(Sockets2.MasterSocket)) Shr 8,
StrToInt(Sockets2.GetPort(Sockets2.MasterSocket)) and $ff]);
Result := command(portcmd,[nil]);
end;
function TFTPForm.TimedOut;
begin
if Aborted then
begin
Aborted := False;
Result := True;
end
else
Result := False;
end;
function TFTPForm.getreply(cmdstring: string): integer;
begin
Result := FTP_ERROR;
if copy(cmdstring,1,5) = 'PASS ' then
DoAddLine('PASS xxxxxx'+#13#10)
else
DoAddLine(cmdstring+#13#10);
if (Sockets1.SocketNumber = INVALID_SOCKET) or not Connected then
begin
DoAddLine('Not Connected'+#13#10);
exit;
end;
Sockets1.Text := cmdstring+#13#10;
if TimedOut or (ErrorReturn <> 0) then
exit;
Result := ReadDisplayLine;
end;
function TFTPForm.command(fmt: string; const args: array of const): integer;
var
Buf: string;
begin
if CmdInProgress then
begin
DoPrintf('Command already in progress, request ignored',[nil]);
Result := -1;
exit;
end;
CmdInProgress := True;
ErrorReturn := 0;
ImBusy;
Buf := Format(fmt,args);
Result := getreply(Buf);
ImFree;
CmdInProgress := False;
end;
function TFTPForm.DoDirList(cmd: string;const args: array of const): integer;
var
Buf: string;
begin
Buf := Format(cmd,args);
RetrieveFile(Buf,'','TYPE A');
end;
procedure TFTPForm.DoPrintf(line: string; const args: array of const);
var
str: string;
begin
str := Format(line,args)+#13#10;
DoAddLine(str);
end;
procedure TFTPForm.DoAddLine(Buff: string);
var
idx,len,i: integer;
begin
len := Length(Buff);
if len > 1 then
begin
for i := 1 to len do
begin
if Buff[i] = #10 then
begin
try
Memo1.Lines.Add(line);
except
on EOutOfResources do
begin
Memo1.Clear;
Memo1.Lines.Add('Cleared output area due to limited resources');
end;
end;
line := '';
end
else
if Buff[i] <> #0 then
line := line + Buff[i];
end
end;
end;
function TFTPForm.ReadDisplayLine: integer;
var
Buff: string;
szBuff: array[0..255] of char absolute Buff;
ch: char;
idx,len: integer;
begin
Result := FTP_ERROR;
repeat
ch := #0;
Buff := Sockets1.Peek;
if TimedOut or (ErrorReturn <> 0) then
exit;
idx := pos(#10,Buff);
if idx > 0 then
begin
len := idx;
Sockets1.SReceive(Sockets1.SocketNumber,@szBuff[1],len);
if TimedOut or (ErrorReturn <> 0) then
exit;
szBuff[0] := chr(len);
GlobalBuff := Buff; {Kludge d'jour}
DoAddLine(Buff);
if Buff[4] <> '-' then { continuation ? }
ch := Buff[1];
end;
until (ch >= '1') and (ch <= '5');
Result := ord(ch) - $30;
end;
procedure TFTPForm.ConnectMNUClick(Sender: TObject);
var
iLength: integer;
iRetCode: integer;
iFlag: integer;
ftp_host: string;
begin
if Connected then
begin
DoPrintf('Already connected to remote host: %s',[Sockets1.IPAddr]);
exit;
end;
line := '';
ErrorReturn := 0;
Memo1.Clear;
LoginDLG.ShowModal;
if LoginDLG.ModalResult = mrCancel then
exit;
ftp_host := LoginDLG.HostName.Text;
Sockets1.Port := '21';
Sockets1.IPAddr := ftp_host;
Sockets1.NonBlocking := False;
ImBusy;
Sockets1.SConnect;
ImFree;
if Aborted or (ErrorReturn <> 0) or (Sockets1.SocketNumber = INVALID_SOCKET) then
begin
DoPrintf('Connection to %s failed',[ftp_host]);
exit;
end;
Connected := True;
doprintf('Local port: %s IP: %s connected to rmt port: %s IP: %s',
[Sockets1.GetPort(Sockets1.SocketNumber),
Sockets1.GetIPAddr(Sockets1.SocketNumber),
Sockets1.GetPeerPort(Sockets1.SocketNumber),
Sockets1.GetPeerIPAddr(Sockets1.SocketNumber)]);
DoPrintf('Connected to %s',[Sockets1.IPAddr]);
repeat
iRetCode := ReadDisplayLine;
until (iRetCode <> FTP_PRELIM) or (Aborted = True);
if command('USER %s',[LoginDLG.UserName.Text]) = FTP_CONTINUE then
if LoginDLG.Password.Text <> '' then
if command('PASS %s',[LoginDlg.PassWord.Text]) = FTP_CONTINUE then
if LoginDLG.Account.Text <> '' then
command('ACCT %s',[LoginDLG.Account.Text]);
if LoginDLG.Directory.Text <> '' then
command('CWD %s',[LoginDLG.Directory.Text]);
EnableDisableMenus;
end;
procedure TFTPForm.DirMNUClick(Sender: TObject);
var
args: string;
begin
args := '*.*';
if InputQuery('Remote Directory Listing','Pattern:',args) then
if args = '*.*' then
DoDirlist('LIST',[nil])
else
DoDirList('LIST %s',[args]);
end;
procedure TFTPForm.QuitMNUClick(Sender: TObject);
begin
command('QUIT',[nil]);
Sockets1.SClose;
Connected := False;
EnableDisableMenus;
end;
procedure TFTPForm.GetMNUClick(Sender: TObject);
var
rtype: string;
begin
GetDLG.ShowModal;
if GetDLG.ModalResult = mrCancel then
exit;
if GetDLG.rbASCII.Checked = True then
rtype := 'TYPE A'
else if GetDLG.rbBINARY.Checked = True then
rtype := 'TYPE I'
else
rtype := 'TYPE E';
RetrieveFile(GetDLG.FileName.Text,GetDlg.LocalName.Text,rtype);
end;
procedure TFTPForm.PutMNUClick(Sender: TObject);
var
PCFile, RMTFile: string;
szPCFile: array[0..255] of char;
NumBytes: integer;
BytesWritten: longint;
Buff: string;
szBuff: array[0..255] of char absolute Buff;
trans_type: string;
input_file: integer;
TotalSendSize: longint;
begin
PutDLG.ShowModal;
if PutDLG.ModalResult = mrCancel then
exit;
if PutDLG.rbASCII.Checked = True then
trans_type := 'TYPE A'
else if PutDLG.rbBINARY.Checked = True then
trans_type := 'TYPE I'
else
trans_type := 'TYPE E';
StrPCopy(szPCFile,PutDLG.FileName.Text);
input_file := _lopen(szPCFile,0);
if input_file = -1 then
begin
Application.MessageBox('Could not open local file','open error',MB_ICONEXCLAMATION);
exit;
end;
TotalSendSize := _llseek(input_file,0,2);
_llseek(input_file,0,0);
DoPrintf('Transferring local file: %s to remote file: %s',
[PutDLG.FileName.Text,PutDLG.RemoteName.Text]);
command(trans_type,[nil]);
Sockets2.NonBlocking := False;
Sockets2.Timeout := 30;
GetFTPListenPort;
command('STOR %s',[PutDLG.RemoteName.Text]);
Sockets2.SAccept;
BytesWritten := 0;
ImBusy;
NumBytes := _lread(input_file,@szBuff[1],255);
while NumBytes > 0 do
begin
szBuff[0] := chr(NumBytes);
Sockets2.Text := Buff;
BytesWritten := BytesWritten + NumBytes;
UpdateGauge(BytesWritten,TotalSendSize);
NumBytes := _lread(input_file,@szBuff[1],255);
if TimedOut then
begin
Sockets1.OOB := 'ABOR'+#13#10;
ReadDisplayLine;
Sockets2.SCancelListen;
Sockets2.SClose;
_lclose(input_file);
ImFree;
DoPrintf('%sTransfer aborted due to you''re request',[#13#10]);
exit;
end;
end;
if NumBytes = -1 then
DoPrintf('File Error, File transfer may be incomplete',[nil]);
Sockets2.SCancelListen;
Sockets2.SClose;
_lclose(input_file);
ImFree;
DoPrintf('Total bytes written to remote host: %s',[IntToStr(BytesWritten)]);
ReadDisplayLine;
CancelGauge;
end;
procedure TFTPForm.ExitMNUClick(Sender: TObject);
begin
if Connected then
begin
DoPrintf('Disconnecting from remote host: %s',[Sockets1.IPAddr]);
QuitMNUClick(self);
end;
Close;
end;
procedure TFTPForm.ChDirMNUClick(Sender: TObject);
var
args: string;
begin
args := '';
if InputQuery('Change Directory','Directory:',args) then
command('CWD %s',[args]);
end;
procedure TFTPForm.ParentMNUClick(Sender: TObject);
begin
command('CDUP',[nil]);
end;
procedure TFTPForm.MkDirMNUClick(Sender: TObject);
var
args: string;
begin
args := '';
if InputQuery('Make Directory','Directory:',args) then
command('MKD %s',[args]);
end;
procedure TFTPForm.RmDirMNUClick(Sender: TObject);
var
args: string;
begin
args := '';
if InputQuery('Remove Directory','Directory:',args) then
command('RMD %s',[args]);
end;
procedure TFTPForm.PwdMNUClick(Sender: TObject);
begin
command('PWD',[nil]);
end;
procedure TFTPForm.RenameMNUClick(Sender: TObject);
begin
RenDLG.ShowModal;
if RenDLG.ModalResult = mrCancel then
exit;
if command('RNFR %s',[RenDLG.FileFrom.Text]) = FTP_CONTINUE then
command('RNTO %s',[RenDLG.FileTo.Text]);
end;
procedure TFTPForm.DeleteMNUClick(Sender: TObject);
var
args: string;
begin
args := '';
if InputQuery('Delete Remote File','File to Delete:',args) then
command('DELE %s',[args]);
end;
procedure TFTPForm.HelpMNUClick(Sender: TObject);
begin
command('HELP',[nil]);
end;
procedure TFTPForm.QuoteMNUClick(Sender: TObject);
var
args: string;
begin
args := '';
if InputQuery('Enter FTP command','Command:',args) then
command('%s',[args]);
end;
procedure TFTPForm.EnableDisableMenus;
var
ed: Boolean;
begin
ed := False;
if Connected then
ed := True;
ChDirMNU.Enabled := ed;
ConnectMNU.Enabled := not ed;
DeleteMNU.Enabled := ed;
DirMNU.Enabled := ed;
GetMNU.Enabled := ed;
HelpMNU.Enabled := ed;
MkDirMNU.Enabled := ed;
PutMNU.Enabled := ed;
QuitMNU.Enabled := ed;
QuoteMNU.Enabled := ed;
RenameMNU.Enabled := ed;
RMDirMNU.Enabled := ed;
PwdMNU.Enabled := ed;
ViewMNU.Enabled := ed;
CancelMNU.Enabled := ed;
ParentMNU.Enabled := ed;
end;
procedure TFTPForm.FormCreate(Sender: TObject);
var
ftpini: TIniFile;
begin
Connected := False;
EnableDisableMenus;
ftpini := TIniFile.Create('FTPPROF.INI');
DirSep := ftpini.ReadString('options','DirSep','');
ViewSep := ftpini.ReadString('options','ViewSep','');
Editor := ftpini.ReadString('options','Editor','');
if (DirSep = '') and (ViewSep = '') and (Editor = '') then
begin
DirSep := '0';
ftpini.WriteString('options','DirSep',DirSep);
ViewSep := '1';
ftpini.WriteString('options','ViewSep',ViewSep);
Editor := 'NOTEPAD.EXE';
ftpini.WriteString('options','Editor',Editor);
end;
if DirSep = '0' then
DirSepMNU.Checked := False
else
DirSepMnu.Checked := True;
if ViewSep = '0' then
ViewSepMNU.Checked := False
else
ViewSepMnu.Checked := True;
end;
procedure TFTPForm.ViewMNUClick(Sender: TObject);
var
rtype: string;
begin
ViewDLG.ShowModal;
if ViewDLG.ModalResult = mrCancel then
exit;
if ViewDLG.rbASCII.Checked = True then
rtype := 'TYPE A'
else if ViewDLG.rbBINARY.Checked = True then
rtype := 'TYPE I'
else
rtype := 'TYPE E';
RetrieveFile(ViewDLG.FileName.Text,'',rtype);
end;
procedure TFTPForm.CancelMNUClick(Sender: TObject);
begin
Aborted := True;
end;
procedure TFTPForm.ImBusy;
begin
FTPForm.Cursor := crHourGlass;
Memo1.Cursor := crHourGlass;
end;
procedure TFTPForm.ImFree;
begin
FTPForm.Cursor := crDefault;
Memo1.Cursor := crDefault;
end;
procedure TFTPForm.EditorMNUClick(Sender: TObject);
var
ftpini: TIniFile;
begin
ftpini := TIniFile.Create('FTPPROF.INI');
Editor := ftpini.ReadString('options','Editor','');
Editor := InputBox('Enter preferred editor','Editor:',Editor);
ftpini.WriteString('options','Editor',Editor);
end;
procedure TFTPForm.DirSepMNUClick(Sender: TObject);
var
ftpini: TIniFile;
begin
ftpini := TIniFile.Create('FTPPROF.INI');
if DirSep = '0' then
begin
DirSep := '1';
DirSepMNU.Checked := True;
end
else
begin
DirSep := '0';
DirSepMNU.Checked := False;
end;
ftpini.WriteString('options','DirSep',DirSep);
end;
procedure TFTPForm.ViewSepMNUClick(Sender: TObject);
var
ftpini: TIniFile;
begin
ftpini := TIniFile.Create('FTPPROF.INI');
if ViewSep = '0' then
begin
ViewSep := '1';
ViewSepMNU.Checked := True;
end
else
begin
ViewSep := '0';
ViewSepMNU.Checked := False;
end;
ftpini.WriteString('options','ViewSep',ViewSep);
end;
function TFTPForm.GetTotalRetrieveSize: longint;
var
left,right: integer;
tmp: string;
begin
left := pos('(',GlobalBuff);
if (left = 0) or (right = 0) then
begin
Result := 0;
exit;
end;
tmp := copy(GlobalBuff,left+1,right-left-1);
right := pos(' ',tmp);
if right <> 0 then
tmp := copy(tmp,1,right-1);
try
Result := StrToInt(tmp);
except
on EConvertError do Result := 0;
end;
end;
procedure TFTPForm.UpdateGauge(BytesWritten, TotalTransferSize: longint);
var
per, oldval: longint;
begin
if TotalTransferSize = 0 then
exit;
if MeterDLG.Visible = False then
MeterDLG.Show;
oldval := MeterDLG.Gauge1.Value;
per := trunc(100.0 / (TotalTransferSize / BytesWritten));
MeterDLG.Gauge1.Value := per;
MeterDLG.Label1.Caption := IntToStr(per)+'% Complete';
if per <> oldval then
MeterDLG.Refresh;
end;
procedure TFTPForm.CancelGauge;
begin
MeterDLG.Hide;
end;
end.